package org.sean.framework.util;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.UncheckedIOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * Created by Sean.xie on 2018/1/24.
 */
public class IOUtil {

    private static final int EOF = -1;

    private static final int DEFAULT_BUFFER_SIZE = 1024;

    private IOUtil() {
    }

    /**
     * 写流信息
     *
     * @param stream 输出流
     * @param b      数据
     * @throws IOException IO异常
     */
    public static void writeStream(OutputStream stream, byte[] b) throws IOException {
        if (stream == null || b == null) {
            return;
        }
        try {
            stream.write(b);
        } finally {
            try {
                stream.close();
            } catch (Exception e) {
                // do nothing
            }
        }
    }

    /**
     * 输入流读取数据
     *
     * @param stream 输入流
     * @return 数据
     * @throws IOException 异常
     */
    public static byte[] readBytes(InputStream stream) throws IOException {
        ByteArrayOutputStream bos = readStream(stream);
        if (bos == null) {
            return null;
        }
        return bos.toByteArray();
    }

    /**
     * 输入流读取数据
     *
     * @param stream 输入流
     * @return 字符串数据
     * @throws IOException 异常
     */
    public static String readString(InputStream stream) throws IOException {
        return new String(readBytes(stream), StandardCharsets.UTF_8);
    }

    /**
     * 输入流读取数据
     *
     * @param stream  输入流
     * @param charset 字符集
     * @return 字符串数据
     * @throws IOException 异常
     */
    public static String readString(InputStream stream, String charset) throws IOException {
        return new String(readBytes(stream), charset);
    }

    /**
     * 输入流读取数据
     *
     * @param stream 输入流
     * @return ByteArrayOutputStream
     * @throws IOException 异常
     */
    public static ByteArrayOutputStream readStream(InputStream stream) throws IOException {
        if (stream == null) {
            return null;
        }
        byte[] b = new byte[1024 * 4];
        int len = -1;
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        while ((len = stream.read(b)) != -1) {
            outStream.write(b, 0, len);
        }
        return outStream;
    }

    /**
     * 复制输入流
     *
     * @param stream 输入流
     * @return 输入流
     * @throws IOException 异常
     */
    public static InputStream copyStream(InputStream stream) throws IOException {
        if (stream == null) {
            return stream;
        }

        return new ByteArrayInputStream(readBytes(stream));
    }

    /**
     * Create a {@code String} from {@link InputStream} with {@link Charset}.
     *
     * @param inputStream source {@link InputStream}
     * @param charset     source {@link String}
     * @return created {@code String}
     */
    public static String toString(InputStream inputStream, String charset) {
        return toString(inputStream, Charset.forName(charset));
    }

    /**
     * Create a {@code String} from {@link InputStream} with {@link Charset}.
     *
     * @param inputStream source {@link InputStream}
     * @param charset     source {@link Charset}
     * @return created {@code String}
     */
    public static String toString(InputStream inputStream, Charset charset) {
        if (inputStream == null) {
            return "";
        }

        try (StringWriter writer = new StringWriter();
             InputStreamReader reader = new InputStreamReader(inputStream, charset);
             BufferedReader bufferedReader = new BufferedReader(reader)) {
            char[] chars = new char[DEFAULT_BUFFER_SIZE];
            int readChars;
            while ((readChars = bufferedReader.read(chars)) != EOF) {
                writer.write(chars, 0, readChars);
            }
            return writer.toString();
        } catch (IOException ex) {
            throw new UncheckedIOException(ex);
        }
    }

    /**
     * Create a {@code String} from {@link InputStream} with default {@link Charset}.
     *
     * @param inputStream source {@link InputStream}
     * @return created {@code String}
     */
    public static String toString(InputStream inputStream) {
        return toString(inputStream, Charset.defaultCharset());
    }

}
